import { FetchResult, MutationResult } from "@apollo/client";
import { ConfirmButtonTransitionState } from "@dashboard/components/ConfirmButton";
import { UserPermissionFragment } from "@dashboard/graphql";
import { Option } from "@saleor/macaw-ui-next";

import { FilterElement, IFilter } from "./components/Filter";

export interface UserError {
  field: string | null;
  message?: string | null;
}

export interface DialogProps {
  open: boolean;
  onClose: () => void;
}

export interface ListSettings<TColumn extends string = string> {
  columns?: TColumn[];
  rowNumber: number;
}

export enum ListViews {
  APPS_LIST = "APPS_LIST",
  ATTRIBUTE_LIST = "ATTRIBUTE_LIST",
  ATTRIBUTE_VALUE_LIST = "ATTRIBUTE_VALUE_LIST",
  CATEGORY_LIST = "CATEGORY_LIST",
  COLLECTION_LIST = "COLLECTION_LIST",
  CUSTOMER_LIST = "CUSTOMER_LIST",
  DRAFT_LIST = "DRAFT_LIST",
  NAVIGATION_LIST = "NAVIGATION_LIST",
  ORDER_LIST = "ORDER_LIST",
  ORDER_DETAILS_LIST = "ORDER_DETAILS_LIST",
  ORDER_DRAFT_DETAILS_LIST = "ORDER_DRAFT_DETAILS_LIST",
  PAGES_LIST = "PAGES_LIST",
  PAGE_TYPES_LIST = "PAGE_TYPES_LIST",
  PLUGINS_LIST = "PLUGIN_LIST",
  PRODUCT_LIST = "PRODUCT_LIST",
  PERMISSION_GROUP_LIST = "PERMISSION_GROUP_LIST",
  PRODUCT_TYPE_LIST = "PRODUCT_TYPE_LIST",
  SALES_LIST = "SALES_LIST",
  DISCOUNTS_LIST = "DISCOUNTS_LIST",
  SHIPPING_METHODS_LIST = "SHIPPING_METHODS_LIST",
  STAFF_MEMBERS_LIST = "STAFF_MEMBERS_LIST",
  VOUCHER_LIST = "VOUCHER_LIST",
  WAREHOUSE_LIST = "WAREHOUSE_LIST",
  WEBHOOK_LIST = "WEBHOOK_LIST",
  TRANSLATION_ATTRIBUTE_VALUE_LIST = "TRANSLATION_ATTRIBUTE_VALUE_LIST",
  GIFT_CARD_LIST = "GIFT_CARD_LIST",
  // Not strictly a list view, but there's a list of variants
  PRODUCT_DETAILS = "PRODUCT_DETAILS",
  VOUCHER_CODES = "VOUCHER_CODES",
  ORDER_REFUNDS = "ORDER_REFUNDS",
  ORDER_TRANSACTION_REFUNDS = "ORDER_TRANSACTION_REFUNDS",
}

export interface ListProps<TColumns extends string = string> {
  disabled: boolean;
  settings?: ListSettings<TColumns>;
  onUpdateListSettings?: <T extends keyof ListSettings<TColumns>>(
    key: T,
    value: ListSettings<TColumns>[T],
  ) => void;
  onListSettingsReset?: () => void;
  filterDependency?: FilterElement;
}

export interface PaginateListProps {
  pageInfo?: {
    hasNextPage: boolean;
    hasPreviousPage: boolean;
  };
  onNextPage: () => void;
  onPreviousPage: () => void;
}

export interface SortPage<TSortKey extends string> {
  sort: Sort<TSortKey>;
  onSort: (field: TSortKey, id?: string) => void;
}

/**
 * @param toggle Will be use to change status of item
 * @param isChecked Returns true for ids of chosen items
 * @param selected  Number of chosen items.
 */

export interface ListActionsWithoutToolbar {
  toggle: (id: string) => void;
  toggleAll: (items: Node[], selected: number) => void;
  isChecked: (id: string) => boolean | undefined;
  selected: number;
}
export type TabListActions<TToolbars extends string> = ListActionsWithoutToolbar &
  Record<TToolbars, React.ReactNode | React.ReactNodeArray>;
export interface ListActions extends ListActionsWithoutToolbar {
  toolbar: React.ReactNode | React.ReactNodeArray;
}
export interface PageListProps<TColumns extends string = string> extends ListProps<TColumns> {
  defaultSettings?: ListSettings<TColumns>;
}

export interface SearchProps {
  onSearchChange: (value: string) => void;
}
export interface SearchPageProps extends SearchProps {
  initialSearch: string;
}
export interface FilterPageProps<TKeys extends string, TOpts extends {}>
  extends FilterProps<TKeys>,
    SearchPageProps,
    TabPageProps {
  filterOpts: TOpts;
}

export interface FilterPagePropsWithPresets<TKeys extends string, TOpts extends {}>
  extends FilterProps<TKeys>,
    SearchPageProps,
    FilterPresetsProps {
  filterOpts: TOpts;
}

export interface FilterProps<TKeys extends string> {
  currencySymbol?: string;
  onFilterChange: (filter: IFilter<TKeys>) => void;
  onFilterAttributeFocus?: (id?: string) => void;
}

export interface FilterPresetsProps {
  selectedFilterPreset: number | undefined;
  filterPresets: string[];
  onFilterPresetsAll: () => void;
  onFilterPresetChange: (id: number) => void;
  onFilterPresetUpdate: (name: string) => void;
  onFilterPresetDelete: (id: number) => void;
  onFilterPresetPresetSave: () => void;
  hasPresetsChanged: () => boolean;
}

export interface TabPageProps {
  currentTab: number | undefined;
  tabs: string[];
  onAll: () => void;
  onTabChange: (tab: number) => void;
  onTabDelete: () => void;
  onTabSave: () => void;
}

export interface ChannelProps {
  selectedChannelId: string;
}

export interface PartialMutationProviderOutput<TData extends {} = {}, TVariables extends {} = {}> {
  opts: MutationResult<TData> & MutationResultAdditionalProps;
  mutate: (variables: TVariables) => Promise<FetchResult<TData>>;
}

export interface Node {
  id: string;
}
export interface SlugNode {
  slug: string;
}

export interface TagNode {
  tag: string;
}

export type Pagination = Partial<{
  after: string;
  before: string;
}>;

export type Dialog<TDialog extends string> = Partial<{
  action: TDialog;
}>;
export type ActiveTab<TTab extends string = string> = Partial<{
  activeTab: TTab;
}>;
export type Filters<TFilters extends string> = Partial<Record<TFilters, string>>;
export type FiltersWithMultipleValues<TFilters extends string> = Partial<
  Record<TFilters, string[]>
>;
export type FiltersAsDictWithMultipleValues<TFilters extends string> = Partial<
  Record<TFilters, Record<string, string[]>>
>;
export type FiltersWithKeyValueValues<TFilters extends string> = Partial<
  Record<TFilters, KeyValue[]>
>;
export type Search = Partial<{
  query: string;
}>;
export type SingleAction = Partial<{
  id: string;
}>;
export type Sort<TSort extends string = string> = Partial<{
  asc: boolean;
  sort: TSort;
}>;
export type BulkAction = Partial<{
  ids: string[];
}>;

export interface ReorderEvent {
  oldIndex: number;
  newIndex: number;
}
export type ReorderAction = (event: ReorderEvent) => void;

export interface FetchMoreProps {
  loading: boolean;
  hasMore: boolean;
  totalCount?: number;
  onFetchMore: () => void;
}

export type TabActionDialog = "save-search" | "delete-search";

export interface UserPermissionProps {
  userPermissions: UserPermissionFragment[];
}

export interface MutationResultAdditionalProps {
  status: ConfirmButtonTransitionState;
}

export interface KeyValue {
  key: string;
  value?: string;
}

export type MinMax = Record<"min" | "max", string>;

export interface FilterOpts<T> {
  active: boolean;
  value: T;
}

export interface AutocompleteFilterOpts extends Partial<FetchMoreProps>, Partial<SearchPageProps> {
  choices: Option[];
  displayValues: Option[];
}

export type Ids = string[];

export enum StatusType {
  INFO = "info",
  ERROR = "error",
  WARNING = "warning",
  SUCCESS = "success",
}

export type RelayToFlat<T extends { edges: Array<{ node: any }> } | null> = T extends {
  edges: Array<{ node: infer U }>;
}
  ? U[]
  : null;
